package paginate

import (
	"gorm.io/gorm"
	"math"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
)

// PageRequest 分页请求
type PageRequest struct {
	Page     int    `form:"page" json:"page"`         // 当前页码
	PageSize int    `form:"pageSize" json:"pageSize"` // 每页大小
	Sort     string `form:"sort" json:"sort"`         // 排序字段
	Order    string `form:"order" json:"order"`       // 排序方式 asc/desc
	Keyword  string `form:"keyword" json:"keyword"`   // 关键词
}

// PageResponse 分页响应
type PageResponse struct {
	Items     interface{} `json:"items"`     // 数据项
	Total     int64       `json:"total"`     // 总数
	Page      int         `json:"page"`      // 当前页码
	PageSize  int         `json:"pageSize"`  // 每页大小
	TotalPage int         `json:"totalPage"` // 总页数
}

// GetPageParams 从Gin上下文获取分页参数
func GetPageParams(c *gin.Context) PageRequest {
	// 默认值
	page := 1
	pageSize := 10
	sort := "created_at"
	order := "desc"

	// 尝试从请求中获取分页参数
	if p, err := strconv.Atoi(c.DefaultQuery("page", "1")); err == nil && p > 0 {
		page = p
	}

	if ps, err := strconv.Atoi(c.DefaultQuery("pageSize", "10")); err == nil && ps > 0 && ps <= 100 {
		pageSize = ps
	}

	if s := c.DefaultQuery("sort", ""); s != "" {
		// 防止SQL注入，只接受字母、数字和下划线
		if strings.ContainsAny(s, "';\"") {
			sort = "created_at" // 恢复默认值
		} else {
			sort = s
		}
	}

	if o := c.DefaultQuery("order", ""); o != "" {
		if strings.ToLower(o) == "asc" {
			order = "asc"
		} else {
			order = "desc"
		}
	}

	return PageRequest{
		Page:     page,
		PageSize: pageSize,
		Sort:     sort,
		Order:    order,
		Keyword:  c.DefaultQuery("keyword", ""),
	}
}

// Paginator GORM分页器
func Paginator(db *gorm.DB, page, pageSize int, sort, order string, out interface{}) (PageResponse, error) {
	var total int64
	var err error

	// 计算总数
	err = db.Count(&total).Error
	if err != nil {
		return PageResponse{}, err
	}

	// 计算总页数
	totalPage := int(math.Ceil(float64(total) / float64(pageSize)))

	// 如果排序字段不为空，添加排序
	if sort != "" {
		db = db.Order(sort + " " + order)
	}

	// 分页查询
	offset := (page - 1) * pageSize
	err = db.Limit(pageSize).Offset(offset).Find(out).Error
	if err != nil {
		return PageResponse{}, err
	}

	return PageResponse{
		Items:     out,
		Total:     total,
		Page:      page,
		PageSize:  pageSize,
		TotalPage: totalPage,
	}, nil
}

// BuildPaginationQuery 构建分页查询
func BuildPaginationQuery(db *gorm.DB, req PageRequest) *gorm.DB {
	if req.Sort != "" {
		db = db.Order(req.Sort + " " + req.Order)
	}

	offset := (req.Page - 1) * req.PageSize
	return db.Limit(req.PageSize).Offset(offset)
}
